/*=============================================================================
	CommonRender.h: Crytek Common render helper functions and structures declarations.
	Copyright (c) 2001 Crytek Studios. All Rights Reserved.

	Revision history:
		* Created by Honich Andrey

=============================================================================*/

#ifndef _COMMONRENDER_H_
#define _COMMONRENDER_H_

#include "Cry_Math.h"

#include "Defs.h"
#include "Cry_Color.h"

#include "STLGlobalAllocator.h"









#if defined (DIRECT3D9) || defined(NULL_RENDERER)
#define VSCONST_INSTDATA   40
#define VSCONST_SKINMATRIX (40)
#define NUM_MAX_BONES_PER_GROUP (100)
#define NUM_MAX_BONES_PER_GROUP_WITH_MB (50)
#define VSCONST_SHAPEDEFORMATION (VSCONST_SKINMATRIX + NUM_MAX_BONES_PER_GROUP_WITH_MB * 4)
#define VSCONST_NOISE_TABLE 64

#elif defined (DIRECT3D10) || defined (CAFE)
#define VSCONST_INSTDATA   0
#define VSCONST_SKINMATRIX 0
#define VSCONST_SHAPEDEFORMATION 0
#define VSCONST_NOISE_TABLE 0
#define NUM_MAX_BONES_PER_GROUP (150)
#define NUM_MAX_BONES_PER_GROUP_WITH_MB (75)

#else
#error Dont know what to define limiting constants to

#endif


//////////////////////////////////////////////////////////////////////
class CRenderer;
extern CRenderer *gRenDev;

class CBaseResource;

//====================================================================

#define CR_LITTLE_ENDIAN

struct SWaveForm;

extern bool gbRgb;

_inline DWORD COLCONV (DWORD clr)
{
  return ((clr & 0xff00ff00) | ((clr & 0xff0000)>>16) | ((clr & 0xff)<<16));
}
_inline void COLCONV (ColorF& col)
{
  float v = col[0];
  col[0] = col[2];
  col[2] = v;
}

_inline void f2d(double *dst, float *src)
{
  for (int i=0; i<16; i++)
  {
    dst[i] = src[i];
  }
}

_inline void d2f(float *dst, double *src)
{
  for (int i=0; i<16; i++)
  {
    dst[i] = (float)src[i];
  }
}

const int HALF_RAND = (RAND_MAX / 2);
_inline float RandomNum()
{
  int rn;
  rn = cry_rand();
  return ((float)(rn - HALF_RAND) / (float)HALF_RAND);
}
_inline float UnsRandomNum()
{
  int rn;
  rn = cry_rand();
  return ((float)rn / (float)RAND_MAX);
}

//=================================================================

//#if defined(PS3)
//	typedef std::map<CCryNameTSCRC,CBaseResource *,CCryNameTSCRC::CmpLex> ResourcesMap; 
//#else 
	typedef std::map<CCryNameTSCRC,CBaseResource *> ResourcesMap; 
//#endif

typedef ResourcesMap::iterator ResourcesMapItor;

typedef std::vector<CBaseResource*, stl::STLGlobalAllocator<CBaseResource*> > ResourcesList;
typedef std::vector<int, stl::STLGlobalAllocator<int> > ResourceIds;

struct SResourceContainer
{
  ResourcesList m_RList;             // List of objects for acces by Id's
  ResourcesMap  m_RMap;              // Map of objects for fast searching
  ResourceIds   m_AvailableIDs;      // Available object Id's for efficient ID's assigning after deleting

	SResourceContainer()
	{
		m_RList.reserve(512);
	}

  ~SResourceContainer();

	void GetMemoryUsage(ICrySizer *pSizer)const 
	{
		pSizer->AddObject(this, sizeof(*this));
		pSizer->AddObject(m_RList);
		pSizer->AddObject(m_RMap);
		pSizer->AddObject(m_AvailableIDs);
	}
};

//#if defined(PS3)
//	typedef std::map<CCryNameTSCRC,SResourceContainer *,CCryNameTSCRC::CmpLex> ResourceClassMap;
//#else 
	typedef std::map<CCryNameTSCRC,SResourceContainer *> ResourceClassMap;
//#endif

typedef ResourceClassMap::iterator ResourceClassMapItor;

class CBaseResource
{
private:
  // Per resource variables
  volatile int32 m_nRefCount;
  int m_nID;
  CCryNameTSCRC m_ClassName;
  CCryNameTSCRC m_NameCRC;

  static ResourceClassMap m_sResources;

public:
  // CCryUnknown interface
  inline void SetRefCounter(int nRefCounter) { m_nRefCount = nRefCounter; }
  virtual int32 AddRef() {
    int32 nRef = CryInterlockedIncrement(&m_nRefCount);
    return nRef;
  }
  virtual int32 Release();
  virtual int GetRefCounter() const { return m_nRefCount; }

  // Constructors.
  CBaseResource() : m_nRefCount(1) {}
  CBaseResource(const CBaseResource& Src);
  CBaseResource& operator=(const CBaseResource& Src);

  // Destructor.
  virtual ~CBaseResource() {};

  CCryNameTSCRC GetNameCRC() { return m_NameCRC; }
  //inline const char *GetName() const { return m_Name.c_str(); }
  //inline const char *GetClassName() const { return m_ClassName.c_str(); }
  inline int GetID() const { return m_nID; }
  inline void SetID(int nID) { m_nID = nID; }

  virtual bool  IsValid();

	static ILINE int RListIndexFromId(int id) { return id - 1; }
	static ILINE int IdFromRListIndex(int idx) { return idx + 1; }

  static ResourceClassMap& GetMaps() { return m_sResources; }
  static CBaseResource *GetResource(const CCryNameTSCRC& className, int nID, bool bAddRef);
  static CBaseResource *GetResource(const CCryNameTSCRC& className, const CCryNameTSCRC& Name, bool bAddRef);
  static SResourceContainer* GetResourcesForClass(const CCryNameTSCRC& className);
  static void ShutDown();

  bool Register(const CCryNameTSCRC& resName, const CCryNameTSCRC& Name);
  bool UnRegister();

	virtual void GetMemoryUsage(ICrySizer *pSizer) const =0;

  static CryCriticalSection s_cResLock;
};

//=================================================================

#if CAPTURE_REPLAY_LOG && defined(WIN32) && defined(DIRECT3D9)
#define MEMREPLAY_WRAP_D3D9
#endif

#if CAPTURE_REPLAY_LOG && defined(WIN32) && defined(DIRECT3D10)
#define MEMREPLAY_WRAP_D3D11
#endif

#ifdef MEMREPLAY_WRAP_D3D9

class MemReplayD3DAnnotation : public IUnknown
{
public:
	static const GUID s_guid;

public:
	MemReplayD3DAnnotation(IDirect3DResource9* pRes, D3DPOOL pool, size_t sz);
	~MemReplayD3DAnnotation();

	virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
	virtual ULONG STDMETHODCALLTYPE AddRef();
	virtual ULONG STDMETHODCALLTYPE Release();

private:
	MemReplayD3DAnnotation(const MemReplayD3DAnnotation&);
	MemReplayD3DAnnotation& operator = (const MemReplayD3DAnnotation&);

private:
	ULONG m_nRefCount;
	IDirect3DResource9* m_pRes;
	D3DPOOL m_pool;
};

inline void MemReplayAnnotateD3DResource(IDirect3DResource9* pResource, D3DPOOL pool, size_t resSz)
{
	if (pResource)
	{
		DWORD sz = sizeof(MemReplayD3DAnnotation*);
		MemReplayD3DAnnotation* pAnnotation;
		if (FAILED(pResource->GetPrivateData(MemReplayD3DAnnotation::s_guid, &pAnnotation, &sz)))
		{
			pAnnotation = new MemReplayD3DAnnotation(pResource, pool, resSz);
			pResource->SetPrivateData(MemReplayD3DAnnotation::s_guid, pAnnotation, sizeof(IUnknown*), D3DSPD_IUNKNOWN);
		}
	}
}

#endif

#ifdef MEMREPLAY_WRAP_D3D11

class MemReplayD3DAnnotation : public IUnknown
{
public:
	static const GUID s_guid;

public:
	MemReplayD3DAnnotation(ID3D11DeviceChild* pRes, size_t sz);
	~MemReplayD3DAnnotation();

	virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
	virtual ULONG STDMETHODCALLTYPE AddRef();
	virtual ULONG STDMETHODCALLTYPE Release();

private:
	MemReplayD3DAnnotation(const MemReplayD3DAnnotation&);
	MemReplayD3DAnnotation& operator = (const MemReplayD3DAnnotation&);

private:
	ULONG m_nRefCount;
	ID3D11DeviceChild* m_pRes;
};

inline void MemReplayAnnotateD3DResource(ID3D11DeviceChild* pResource, size_t resSz)
{
	if (pResource)
	{
		UINT sz = sizeof(MemReplayD3DAnnotation*);
		MemReplayD3DAnnotation* pAnnotation;
		if (FAILED(pResource->GetPrivateData(MemReplayD3DAnnotation::s_guid, &sz, &pAnnotation)))
		{
			pAnnotation = new MemReplayD3DAnnotation(pResource, resSz);
			pResource->SetPrivateDataInterface(MemReplayD3DAnnotation::s_guid, pAnnotation);
		}
	}
}

#endif

#endif
